/*
 * Copyright (c) 2012 Banaanvraag
 * MIT Licence
 */
package banaanvraag.tools.stackf;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;

/**
 * Class for simple text-based human-readable storage like configuration files.
 * The format is [key] = [value], where every line is one key-value pair.
 * It is recommended to group keys in a way like "multiverse.parallel-universes = 10e500"
 * Everything is returned as a string for the sake of simplicity.
 * @author Luc
 */
public class StackFFile {
    private HashMap<String, String> vals = new HashMap<>();
    
    private String fileName;
    private boolean beVerbose = false;
    
    /**
     * Construct a new StackFFile from a file that already exists.
     * Reads every line and converts it into key-value pairs
     * @param name The filename of the file to read from
     * @throws FileNotFoundException When the file does not exist
     * @throws IOException When the read failed for some reason
     */
    public StackFFile(String name) throws FileNotFoundException, IOException {
        BufferedReader in = new BufferedReader(new FileReader(name));
        
        fileName = name;
        
        String lineRead;
        String[] lineParts;
        while(in.ready()) {
            lineRead = in.readLine();
            if(lineRead.startsWith("#")) {
                continue;
            }
            lineParts = lineRead.split(" = ", 2);
            
            vals.put(lineParts[0], lineParts[1]);
        }
    }
    
    /**
     * Construct a StackFFile for a file that does not exist yet
     */
    public StackFFile() {
        
    }
    
    /**
     * Write all the data of the StackFFile to a file.
     * @param name The filename of the file to write to (doesn't have to exist)
     * @return The number of lines written
     * @throws IOException If the write fails for some reason
     */
    public int saveToFile(String name) throws IOException {
        BufferedWriter out = new BufferedWriter(new FileWriter(name));
        
        int i = 0;
        if(beVerbose) {
            out.write("#StackFFile-1.0; tools-1.0");
            out.newLine();
            out.write("#keys: " + vals.size());
            out.newLine();
            i += 2;
        }
        
        Iterator<String> keyIterator = vals.keySet().iterator();
        String currentKey;
        while(keyIterator.hasNext()) {
            currentKey = keyIterator.next();
            out.write(currentKey + " = " + vals.get(currentKey));
            out.newLine();
            i++;
        }
        
        out.flush();
        out.close();
        
        return i;
    } 
    
    /**
     * Attempts to save the file to the file it was originally read from.
     * @return The number of lines written, 0 if this file was new and therefore no original filename had.
     * @throws IOException If the write fails for some reason.
     */
    public int saveToFile() throws IOException {
        if(fileName == null) {
            return 0;
        }
        return saveToFile(fileName);
    }
    
    /**
     * Checks if a key exists in the file
     * @param key The key to check
     * @return true if it exists, false otherwise.
     */
    public boolean hasKey(String key) {
        return vals.containsKey(key);
    }
    
    /**
     * Returns the value belonging to the key
     * @param key The key of the value
     * @return The value belonging to the key
     */
    public String get(String key) {
        if(!hasKey(key)) {
            return "";
        }
        return vals.get(key);
    }
    
    /**
     * Adds a key-value pair to the StackFFile
     * @param key The key of the pair
     * @param value The value of the pair
     */
    public void add(String key, String value) {
        vals.put(key, value);
    }
    
    /**
     * Set to true if additional information has to be written as a header of the file.
     * @param flag True for additional info, false for nothing.
     */
    public void setVerbose(boolean flag) {
        beVerbose = flag;
    }
}
